package team.mutong.taxi.dtw;

import java.sql.Blob;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import team.mutong.taxi.domain.DtwFeature;
import team.mutong.taxi.domain.GPSPoint;
import team.mutong.taxi.utils.ChangeType;
import team.mutong.taxi.utils.EuclideanMetric;
import weka.core.parser.java_cup.non_terminal;

/**
 * @author TomWang
 * @email wanghuochen@outlook.com
 * @date 2016年5月9日 上午11:26:27
 * @version 1.0
 */
public class DtwCroe {
	/**
	 * 计算两组GPS坐标之间的DTW距离
	 * @author TomWang
	 * @param List<GPSPoint> source
	 * @param List<GPSPoint> test
	 * @return
	 */
	public static double getExeDistence(List<GPSPoint> source, List<GPSPoint> test) {
		double[][] distance = new double[source.size()+1][test.size()+1];
		double[][] output = new double[source.size()+1][test.size()+1];
		for(int i=1; i<=source.size(); i++)	
			output[i][0] = Double.MAX_VALUE;
		for(int i=1; i<=test.size(); i++)
			output[0][i] = Double.MAX_VALUE;
		for(int i=1;i<=source.size();i++)
			for(int j=1;j<=test.size();j++)
				distance[i][j]=EuclideanMetric.getEDistence(source.get(i-1), test.get(j-1));		  //计算点与点之间的欧式距离

		for(int i=1;i<=source.size();i++)
			for(int j=1;j<=test.size();j++)
				output[i][j]=Math.min(Math.min(output[i-1][j-1], output[i][j-1]),output[i-1][j])+distance[i][j];//DP过程，计算DTW距离

		int i = 0;//计数
		int j = source.size();
		int k = test.size();
		while (j>0||k>0) {
			double a = output[j-1][k];
			double b = output[j][k-1];
			double c = output[j-1][k-1];
			if (a>b) {
				if (b>c) {
					j=j-1;
					k=k-1;
				}else{
					k=k-1;
				}
			}else{
				if(a>c){
					j=j-1;
					k=k-1;
				}else {
					j=j-1;
				}
			}
			i++;
		}
		return output[source.size()][test.size()]/i;
	}
	/**
	 * 计算两组GPS坐标之间的DTW距离
	 * @author TomWang
	 * @param double[][] source
	 * @param double[][] test
	 * @return
	 */
	public static double getExeDistence(double[][] source, double[][] test) {
		double[][] distance = new double[source.length+1][test.length+1];
		double[][] output = new double[source.length+1][test.length+1];
		for(int i=1; i<=source.length; i++)	
			output[i][0] = Double.MAX_VALUE;
		for(int i=1; i<=test.length; i++)
			output[0][i] = Double.MAX_VALUE;
		for(int i=1;i<=source.length;i++)
			for(int j=1;j<=test.length;j++)
				distance[i][j]=EuclideanMetric.getEDistence(source[i-1], test[j-1]);		  //计算点与点之间的欧式距离

		for(int i=1;i<=source.length;i++)
			for(int j=1;j<=test.length;j++)
				output[i][j]=Math.min(Math.min(output[i-1][j-1], output[i][j-1]),output[i-1][j])+distance[i][j];//DP过程，计算DTW距离
		int i = 0;//计数
		int j = source.length;
		int k = test.length;
		while (j>0||k>0) {
			double a = output[j-1][k];
			double b = output[j][k-1];
			double c = output[j-1][k-1];
			if (a>b) {
				if (b>c) {
					j=j-1;
					k=k-1;
				}else{
					k=k-1;
				}
			}else{
				if(a>c){
					j=j-1;
					k=k-1;
				}else {
					j=j-1;
				}
			}
			i++;
		}
		return output[source.length][test.length]/i;
	}
	/**
	 * 根据DTW匹配得到的结果
	 * @param trainSet 训练集
	 * @param testSet 测试集
	 * @return 匹配得到的结果
	 * @author TomWang
	 */
	public static List<DtwFeature> getDtwObject(List<Map<String, Object>> trainSet, Map<String, Object> testSet){
		List<DtwFeature> result = new ArrayList<>();
		int n = 5;//阈值
		int m = 10;//阈值
		String testSetRoad = ChangeType.blobChangetoString((byte[]) testSet.get("POLYLINE"));		//取出测试用的路径
		List<GPSPoint> testSetGpsPoint = ChangeType.changeToObject(testSetRoad);//将坐标转换成二维数组
//		double testSetToteRoad = 0.0;//测试路径的长度
//		for(int i=1; i<testSetGpsPoint.size(); i++){
//			testSetToteRoad += EuclideanMetric.getEDistence(testSetGpsPoint.get(i-1), testSetGpsPoint.get(i));
//		}
		for(Map<String, Object> trainSetTemp: trainSet){
			int indexStart = 0;
			int indexend = 0;
			String trainSetRoad = ChangeType.blobChangetoString((byte[]) trainSetTemp.get("POLYLINE"));
			List<GPSPoint> trainSetGpsPoint = ChangeType.changeToObject(trainSetRoad);//将坐标转换成二维数组
			for (int i=0; i<trainSetGpsPoint.size(); i++) {//找到gps起点的位置
				double distence2 = EuclideanMetric.getEDistence(trainSetGpsPoint.get(i), testSetGpsPoint.get(testSetGpsPoint.size()-1));
				double distence1 = EuclideanMetric.getEDistence(trainSetGpsPoint.get(i), testSetGpsPoint.get(0));
				if (distence1<=n){
					indexStart = i;
				}
				if (distence2<=n){
					indexend = i;
				}
				if(indexStart >0 && indexend >0 && indexStart!=indexend){
					List<GPSPoint> Road = new ArrayList<>();
					if (indexStart>indexend) {
						break;
					} 
					for(;indexStart<=indexend;indexStart++){
						Road.add(trainSetGpsPoint.get(indexStart));
					}
					double distence = 0;
					for(int j=1; j<Road.size(); j++){
						distence += EuclideanMetric.getEDistence(Road.get(j-1), Road.get(j));
					}
					double rightDteValue = DtwCroe.getExeDistence(Road,testSetGpsPoint);
					if(rightDteValue<=m){//1是一个阈值
						DtwFeature detFeature = new DtwFeature(trainSetTemp, Road, distence, 1);
						result.add(detFeature);
						break;
					}
				}
			}
		}
		return result;
	}
}
